/*
 * Copyright (c) 2009, Katholieke Universiteit Leuven
 * All rights reserved.
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 * 
 *     * Redistributions of source code must retain the above copyright notice,
 *       this list of conditions and the following disclaimer.
 *     * Redistributions in binary form must reproduce the above copyright notice,
 *       this list of conditions and the following disclaimer in the documentation
 *       and/or other materials provided with the distribution.
 *     * Neither the name of the Katholieke Universiteit Leuven nor the names of
 *       its contributors may be used to endorse or promote products derived from
 *       this software without specific prior written permission.
 * 
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */
/**
 * @addtogroup component
 * @{
 * @defgroup components The core LooCI component system
 * @{
 */
/**
 * @file
 * Header file for the core LooCI component system
 * @author Wouter Horré <wouter.horre@cs.kuleuven.be>
 */
#ifndef __LOOCI_COMPONENTS_H__
#define __LOOCI_COMPONENTS_H__

#include "contiki.h"
#include "sys/cc.h"
#include "events/eventtype.h"

/**
 * The component id for a component that hasn't been initialized.
 */
#define COMPONENT_ID_NONE 0

/**
 * The component states
 */
enum component_state {
  COMPONENT_STATE_NONE = 0,
  COMPONENT_STATE_ACTIVE = 1,
  COMPONENT_STATE_DEACTIVATED = 2,
};

/**
 * A component.
 */
struct component {
  struct component * next;
  u8_t id;
  struct process * process;
  looci_eventtype_t * interfaces;
  looci_eventtype_t * receptacles;
  enum component_state state;
};

/**
 * Declare a component thread.
 *
 * @param name The component name (declared with COMPONENT())
 * @param ev The Contiki event that caused the component to be scheduled
 * @param data The data passed along with the Contiki event
 *
 * @hideinitializer
 */
#define COMPONENT_THREAD(name, ev, data) PROCESS_THREAD(name##_process, ev, data)

/**
 * Declare a component.
 *
 * @param name The name of the component struct that will be created.
 *
 * @param ctype A string defining the component type.
 *
 * @hideinitializer
 */
#define COMPONENT(name, ctype) \
  PROCESS(name##_process,ctype); \
  COMPONENT_THREAD(name, ev, data); \
  struct component name = { NULL, COMPONENT_ID_NONE, &name##_process, name##_interfaces, name##_receptacles, COMPONENT_STATE_DEACTIVATED }

#if ! CC_NO_VA_ARGS
/**
 * Declare the interfaces of a component.
 *
 * @param name The name of the component.
 *
 * @param ... The eventtypes the component publishes.
 *
 * @note One of COMPONENT_INTERFACES or COMPONENT_NO_INTERFACES is mandatory! 
 *       The declaration must be done before the component declaration!
 *
 * @hideinitializer
 */
#define COMPONENT_INTERFACES(name, ...) \
  looci_eventtype_t name##_interfaces[] = {__VA_ARGS__, 0 }

/**
 * Declare the absence of interfaces on a component.
 *
 * @param name The name of the component.
 *
 * @note One of COMPONENT_INTERFACES or COMPONENT_NO_INTERFACES is mandatory! 
 *       The declaration must be done before the component declaration!
 *
 * @hideinitializer
 */
#define COMPONENT_NO_INTERFACES(name) \
  looci_eventtype_t name##_interfaces[] = { 0 }

/**
 * Declare the receptacles of a component.
 *
 * @param name The name of the component.
 *
 * @param ... The eventtypes the component consumes.
 *
 * @note One of COMPONENT_RECEPTACLES or COMPONENT_NO_RECEPTACLES is mandatory! 
 *       The declaration must be done before the component declaration!
 *
 * @hideinitializer
 */
#define COMPONENT_RECEPTACLES(name, ...) \
  looci_eventtype_t name##_receptacles[] = {__VA_ARGS__, 0}

/**
 * Declare the absence of receptacles on a component.
 *
 * @param name The name of the component.
 *
 * @note One of COMPONENT_RECEPTACLES or COMPONENT_NO_RECEPTACLES is mandatory! 
 *       The declaration must be done before the component declaration!
 *
 * @hideinitializer
 */
#define COMPONENT_NO_RECEPTACLES(name) \
  looci_eventtype_t name##_receptacles[] = { 0 }

#else // ! CC_NO_VA_ARGS
#error "C compiler must support __VA_ARGS__ macro"
#endif // ! CC_NO_VA_ARGS
/**
 * Mark the beginning of a COMPONENT_THREAD
 *
 * @hideinitializer
 */
#define COMPONENT_BEGIN PROCESS_BEGIN

/**
 * Mark the end of a COMPONENT_THREAD
 *
 * @hideinitializer
 */
#define COMPONENT_END PROCESS_END

/**
 * Get the type of a component
 *
 * @hideinitializer
 */
#define COMPONENT_TYPE(comp) (comp->process->name)

#if ! CC_NO_VA_ARGS
#ifndef BUILD_COMPONENT
/**
 * Declare the components define in a file.
 *
 * @hideinitializer
 */
#define LOOCI_COMPONENTS(...) \
struct component * const autostart_components[] = {__VA_ARGS__, NULL}
#else // BUILD_COMPONENT
// We trick contiki by setting our components as autostart processes
// We can then access them by using elfloader_autostart_processes
#define LOOCI_COMPONENTS AUTOSTART_PROCESSES
#endif // BUILD_COMPONENT
#else // ! CC_NO_VA_ARGS
#error "C compiler must support __VA_ARGS__ macro"
#endif // ! CC_NO_VA_ARGS

CLIF extern struct component * const autostart_components[];

#endif /* __LOOCI_COMPONENTS_H__ */

/** @} */
/** @} */
